library ieee;
use ieee.std_logic_1164.all;

-- This arbitrary state machine is probably not very useful in reality, but demonstrates 

ENTITY logicblock IS
    PORT (clock, reset, input, match, table_full_in : IN STD_LOGIC;
          location: IN STD_LOGIC_VECTOR(31 downto 0);
          state: OUT STD_LOGIC_VECTOR(4 downto 0);
          read_en, outputpulse, ack, compare_write, port_write,output_write,table_write, table_shift,add_choose, update_location_en, shift_direction, table_full, write_choose, tablestart, port_write_choose, shift_full: OUT STD_LOGIC);
END logicblock;


ARCHITECTURE Behavior OF logicblock IS


-- Define the state variable
TYPE State_type IS (resetstate_1, resetstate_2, readstate, dacheck_1, dacheck_2, dacheck_3, daupdate_1, daupdate_1_1, daupdate_2, daupdate_2_1, sacheck_1, sacheck_2, saupdate_1, saupdate_1_1, saupdate_2, saupdate_3, saupdate_4, saupdate_5, saupdate_6, saupdate_7, outputstate );
SIGNAL my_state_reg, my_state_next: State_type:= resetstate_1;


BEGIN

-- Update state on rising edges or a reset
PROCESS(Clock, reset)
	BEGIN
		IF(reset ='1') then 
		my_state_reg <= resetstate_1;
		elsif(clock'event and clock='1') then
			my_state_reg<=my_state_next;
		end if;
		end process;

-- Next State Calculation
PROCESS(my_state_reg, input, match, location, table_full_in) 
	Begin
		CASE my_state_reg IS
			WHEN resetstate_1 =>
				IF input = '1' AND (location = "00000000000000000000000000000001"
					OR location = "00000000000000000000000000000010"
					OR location = "00000000000000000000000000000100"
					OR location = "00000000000000000000000000001000"
					OR location = "00000000000000000000000000010000"
					OR location = "00000000000000000000000000100000"
					OR location = "00000000000000000000000001000000"
					OR location = "00000000000000000000000010000000"
					OR location = "00000000000000000000000100000000"
					OR location = "00000000000000000000001000000000"
					OR location = "00000000000000000000010000000000"
					OR location = "00000000000000000000100000000000"
					OR location = "00000000000000000001000000000000"
					OR location = "00000000000000000010000000000000"
					OR location = "00000000000000000100000000000000"
					OR location = "00000000000000001000000000000000"
					OR location = "00000000000000010000000000000000"
					OR location = "00000000000000100000000000000000"
					OR location = "00000000000001000000000000000000"
					OR location = "00000000000010000000000000000000"
					OR location = "00000000000100000000000000000000"
					OR location = "00000000001000000000000000000000"
					OR location = "00000000010000000000000000000000"
					OR location = "00000000100000000000000000000000"
					OR location = "00000001000000000000000000000000"
					OR location = "00000010000000000000000000000000"
					OR location = "00000100000000000000000000000000"
					OR location = "00001000000000000000000000000000"
					OR location = "00010000000000000000000000000000"
					OR location = "00100000000000000000000000000000"
					OR location = "01000000000000000000000000000000"
					OR location = "10000000000000000000000000000000") THEN my_state_next <= readstate;
				 ELSIF location = "00000000000000000000000000000001" 
					OR location = "00000000000000000000000000000010"
					OR location = "00000000000000000000000000000100"
					OR location = "00000000000000000000000000001000"
					OR location = "00000000000000000000000000010000"
					OR location = "00000000000000000000000000100000"
					OR location = "00000000000000000000000001000000"
					OR location = "00000000000000000000000010000000"
					OR location = "00000000000000000000000100000000"
					OR location = "00000000000000000000001000000000"
					OR location = "00000000000000000000010000000000"
					OR location = "00000000000000000000100000000000"
					OR location = "00000000000000000001000000000000"
					OR location = "00000000000000000010000000000000"
					OR location = "00000000000000000100000000000000"
					OR location = "00000000000000001000000000000000"
					OR location = "00000000000000010000000000000000"
					OR location = "00000000000000100000000000000000"
					OR location = "00000000000001000000000000000000"
					OR location = "00000000000010000000000000000000"
					OR location = "00000000000100000000000000000000"
					OR location = "00000000001000000000000000000000"
					OR location = "00000000010000000000000000000000"
					OR location = "00000000100000000000000000000000"
					OR location = "00000001000000000000000000000000"
					OR location = "00000010000000000000000000000000"
					OR location = "00000100000000000000000000000000"
					OR location = "00001000000000000000000000000000"
					OR location = "00010000000000000000000000000000"
					OR location = "00100000000000000000000000000000"
					OR location = "01000000000000000000000000000000"
					OR location = "10000000000000000000000000000000" THEN my_state_next <= resetstate_1;
				ELSE my_state_next <= resetstate_2;
				END IF;
			WHEN resetstate_2 =>
				my_state_next <= resetstate_1;
			WHEN readstate =>
				my_state_next <= dacheck_1;
			WHEN dacheck_1 =>
				my_state_next <= dacheck_2;
			WHEN dacheck_2 =>
				my_state_next <= dacheck_3;
			WHEN dacheck_3 =>
				IF match = '1' AND (location = "00000000000000000000000000000001" 
					OR location = "00000000000000000000000000000010"
					OR location = "00000000000000000000000000000100"
					OR location = "00000000000000000000000000001000"
					OR location = "00000000000000000000000000010000"
					OR location = "00000000000000000000000000100000"
					OR location = "00000000000000000000000001000000"
					OR location = "00000000000000000000000010000000"
					OR location = "00000000000000000000000100000000"
					OR location = "00000000000000000000001000000000"
					OR location = "00000000000000000000010000000000"
					OR location = "00000000000000000000100000000000"
					OR location = "00000000000000000001000000000000"
					OR location = "00000000000000000010000000000000"
					OR location = "00000000000000000100000000000000"
					OR location = "00000000000000001000000000000000"
					OR location = "00000000000000010000000000000000"
					OR location = "00000000000000100000000000000000"
					OR location = "00000000000001000000000000000000"
					OR location = "00000000000010000000000000000000"
					OR location = "00000000000100000000000000000000"
					OR location = "00000000001000000000000000000000"
					OR location = "00000000010000000000000000000000"
					OR location = "00000000100000000000000000000000"
					OR location = "00000001000000000000000000000000"
					OR location = "00000010000000000000000000000000"
					OR location = "00000100000000000000000000000000"
					OR location = "00001000000000000000000000000000"
					OR location = "00010000000000000000000000000000"
					OR location = "00100000000000000000000000000000"
					OR location = "01000000000000000000000000000000")
					AND (table_full_in = '0') THEN my_state_next <= daupdate_1;
				ELSIF match = '1' AND (location = "10000000000000000000000000000000" OR table_full_in =  '1') THEN my_state_next <= daupdate_1_1;
				ELSE my_state_next <= sacheck_1;
				END IF;
			WHEN daupdate_1 =>
				my_state_next <= daupdate_2;
			WHEN daupdate_1_1 =>
				IF table_full_in = '0' THEN my_state_next <= daupdate_2;
				ELSE my_state_next <= daupdate_2_1;
				END IF;
			WHEN daupdate_2 =>
				my_state_next <= sacheck_1;
			WHEN daupdate_2_1 =>
				my_state_next <= sacheck_1;
			WHEN sacheck_1 =>
				my_state_next <= sacheck_2;
			WHEN sacheck_2 =>
				IF match = '1' AND table_full_in = '0' THEN my_state_next <= saupdate_1;
				ELSIF match ='1' AND table_full_in = '1' THEN my_state_next <= saupdate_1_1;
				ELSIF match = '0' AND location = "00000000000000000000000000000001" AND table_full_in = '0' THEN my_state_next <= saupdate_5;
				ELSIF match = '0' AND table_full_in = '1' THEN my_state_next <= saupdate_6;
				ELSE my_state_next <= saupdate_3;
				END IF;
			WHEN saupdate_1 =>
				my_state_next <= saupdate_2;
			WHEN saupdate_1_1 =>
				my_state_next <= saupdate_7;
			WHEN saupdate_2 =>
				my_state_next <= outputstate;
			WHEN saupdate_3 =>
				my_state_next <= saupdate_4;
			WHEN saupdate_4 =>
				my_state_next <= outputstate;
			WHEN saupdate_5 =>
				my_state_next <= outputstate;
			WHEN saupdate_6 =>
				my_state_next <= saupdate_7;
			WHEN saupdate_7 =>
				my_state_next <= outputstate;
			WHEN outputstate =>
				IF input = '1' THEN my_state_next <= readstate;
				ELSE my_state_next <= resetstate_1;
				END IF;
		END CASE;
END PROCESS;


-- Output Calculation
PROCESS (my_state_reg)  -- Moore output logic
begin
ack <= '0'; -- default value
outputpulse <= '0';
read_en <= '0';
compare_write<= '0'; 
port_write<= '0';
output_write<= '0';
table_write<= '0';
table_shift<= '0';
add_choose<= '0';
update_location_en<= '0';
shift_direction<= '0';
table_full<= '0';
write_choose<= '0';
tablestart<= '0';
port_write_choose<= '0';
shift_full<= '0';


case my_state_reg is

when resetstate_1 => ack <= '0'; outputpulse <= '0';state <= "00000"; read_en <= '0'; compare_write<= '0'; port_write<= '0'; output_write<= '0'; table_write<='0'; table_shift<='0'; add_choose<='0'; update_location_en<= '0'; shift_direction<= '0'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0';   
when resetstate_2 => ack <= '0'; outputpulse <= '0';state <= "00000"; read_en <= '0'; compare_write<= '0'; port_write<= '0'; output_write<= '0'; table_write<='0'; table_shift<='0'; add_choose<='0'; update_location_en<= '1'; shift_direction<= '0'; table_full<='0'; write_choose<= '0'; tablestart<= '1'; port_write_choose<= '0'; shift_full<= '0';
when readstate => ack <= '1'; outputpulse <= '0';state <= "00001"; read_en <= '1'; compare_write<= '0'; port_write<= '0'; output_write<= '0'; table_write<='0'; table_shift<='0'; add_choose<='0'; update_location_en<= '0'; shift_direction<= '0'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0';
when dacheck_1 => ack <= '1'; outputpulse <= '0';state <= "00010"; read_en <= '0'; compare_write<= '1'; port_write<= '0'; output_write<= '0'; table_write<='0'; table_shift<='0'; add_choose<='1'; update_location_en<= '0'; shift_direction<= '0'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0';
when dacheck_2 => ack <= '1'; outputpulse <= '0';state <= "00011"; read_en <= '0'; compare_write<= '0'; port_write<= '1'; output_write<= '0'; table_write<='0'; table_shift<='0'; add_choose<='0'; update_location_en<= '0'; shift_direction<= '0'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0';
when dacheck_3 => ack <= '1'; outputpulse <= '0';state <= "00100"; read_en <= '0'; compare_write<= '0'; port_write<= '0'; output_write<= '1'; table_write<='0'; table_shift<='0'; add_choose<='0'; update_location_en<= '0'; shift_direction<= '0'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0';
when daupdate_1 => ack <= '1'; outputpulse <= '0';state <= "00101"; read_en <= '0'; compare_write<= '0'; port_write<= '0'; output_write<= '0'; table_write<='0'; table_shift<='1'; add_choose<='0'; update_location_en<= '1'; shift_direction<= '0'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0';
when daupdate_1_1 => ack <= '1'; outputpulse <= '0';state <= "00110"; read_en <= '0'; compare_write<= '0'; port_write<= '0'; output_write<= '0'; table_write<='0'; table_shift<='1'; add_choose<='0'; update_location_en<= '0'; shift_direction<= '0'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0'; 
when daupdate_2 => ack <= '1'; outputpulse <= '0';state <= "00111"; read_en <= '0'; compare_write<= '0'; port_write<= '0'; output_write<= '0'; table_write<='1'; table_shift<='0'; add_choose<='0'; update_location_en<= '1'; shift_direction<= '1'; table_full<='0'; write_choose<= '1'; tablestart<= '0'; port_write_choose<= '1'; shift_full<= '0';
when daupdate_2_1 => ack <= '1'; outputpulse <= '0';state <= "01000"; read_en <= '0'; compare_write<= '0'; port_write<= '0'; output_write<= '0'; table_write<='1'; table_shift<='0'; add_choose<='0'; update_location_en<= '0'; shift_direction<= '0'; table_full<='0'; write_choose<= '1'; tablestart<= '0'; port_write_choose<= '1'; shift_full<= '0'; 
when sacheck_1 => ack <= '1'; outputpulse <= '0';state <= "01001"; read_en <= '0'; compare_write<= '1'; port_write<= '0'; output_write<= '0'; table_write<='0'; table_shift<='0'; add_choose<='0'; update_location_en<= '0'; shift_direction<= '0'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0';
when sacheck_2 => ack <= '1'; outputpulse <= '0';state <= "01010"; read_en <= '0'; compare_write<= '0'; port_write<= '1'; output_write<= '0'; table_write<='0'; table_shift<='0'; add_choose<='0'; update_location_en<= '0'; shift_direction<= '0'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0';
when saupdate_1 => ack <= '1'; outputpulse <= '0';state <= "01011"; read_en <= '0'; compare_write<= '0'; port_write<= '0'; output_write<= '0'; table_write<='0'; table_shift<='1'; add_choose<='0'; update_location_en<= '1'; shift_direction<= '0'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0';
when saupdate_1_1 => ack <= '1'; outputpulse <= '0';state <= "01100"; read_en <= '0'; compare_write<= '0'; port_write<= '0'; output_write<= '0'; table_write<='0'; table_shift<='1'; add_choose<='0'; update_location_en<= '0'; shift_direction<= '0'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0';
when saupdate_2 => ack <= '1'; outputpulse <= '0';state <= "01101"; read_en <= '0'; compare_write<= '0'; port_write<= '0'; output_write<= '0'; table_write<='1'; table_shift<='0'; add_choose<='0'; update_location_en<= '1'; shift_direction<= '1'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0';
when saupdate_3 => ack <= '1'; outputpulse <= '0';state <= "01110"; read_en <= '0'; compare_write<= '0'; port_write<= '0'; output_write<= '0'; table_write<='1'; table_shift<='0'; add_choose<='0'; update_location_en<= '0'; shift_direction<= '0'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0';
when saupdate_4 => ack <= '1'; outputpulse <= '0';state <= "01111"; read_en <= '0'; compare_write<= '0'; port_write<= '0'; output_write<= '0'; table_write<='0'; table_shift<='0'; add_choose<='0'; update_location_en<= '1'; shift_direction<= '1'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0';
when saupdate_5 => ack <= '1'; outputpulse <= '0';state <= "10000"; read_en <= '0'; compare_write<= '0'; port_write<= '0'; output_write<= '0'; table_write<='1'; table_shift<='0'; add_choose<='0'; update_location_en<= '0'; shift_direction<= '0'; table_full<='1'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0';
when saupdate_6 => ack <= '1'; outputpulse <= '0';state <= "10001"; read_en <= '0'; compare_write<= '0'; port_write<= '0'; output_write<= '0'; table_write<='0'; table_shift<='1'; add_choose<='0'; update_location_en<= '0'; shift_direction<= '0'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '1';
when saupdate_7 => ack <= '1'; outputpulse <= '0';state <= "10010"; read_en <= '0'; compare_write<= '0'; port_write<= '0'; output_write<= '0'; table_write<='1'; table_shift<='0'; add_choose<='0'; update_location_en<= '0'; shift_direction<= '0'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0';
when outputstate => ack <= '0'; outputpulse <= '1';state <= "10011"; read_en <= '0'; compare_write<= '0'; port_write<= '0'; output_write<= '0'; table_write<='0'; table_shift<='0'; add_choose<='0'; update_location_en<= '0'; shift_direction<= '0'; table_full<='0'; write_choose<= '0'; tablestart<= '0'; port_write_choose<= '0'; shift_full<= '0';

end case;
end process;


END Behavior;